<?php

/**
 * @desc 银联支付UnionPay接口 Core函数
  * @version 0.1
 * @copyright 2015-09-19
 */


/**
 * @desc 签名
 *
 * @param String $params_str 提交的参数，包括订单号、金额等
 * @param string $unionpay_sign_cert_path 签名证书路径
 * @param string $unionpay_sign_cert_pwd 签名证书密码
 * @return unknown
 */
function sign(&$params, $unionpay_sign_cert_path, $unionpay_sign_cert_pwd) {
	if(isset($params['transTempUrl'])){
		unset($params['transTempUrl']);
	}


	// 转换成key=val&串
	$params_str = ParamsToString($params);
	$params_sha1x16 = sha1($params_str, FALSE);

	$private_key = getPrivateKey ($unionpay_sign_cert_path, $unionpay_sign_cert_pwd);

	// 签名
	$sign_falg = openssl_sign($params_sha1x16, $signature, $private_key, OPENSSL_ALGO_SHA1);
	if($sign_falg) {
		$signature_base64 = base64_encode($signature);
		$params['signature'] = $signature_base64;
	} else {
		//printf(">>>>>签名失败<<<<<<<");
		$params['signature'] = '';
	}
	// echo $params ['signature'].'<br/>';
}

/**
 * @desc 返回(签名)证书key
 *
  * @param string $unionpay_sign_cert_path 签名证书路径
 * @param string $unionpay_sign_cert_pwd 签名证书密码
 *
 * @return unknown
 */
function getPrivateKey($unionpay_sign_cert_path, $unionpay_sign_cert_pwd) {
	$pkcs12 = file_get_contents( $unionpay_sign_cert_path );
	openssl_pkcs12_read( $pkcs12, $certs, $unionpay_sign_cert_pwd);
	return $certs ['pkey'];
}

/**
 * @desc 取.pfx格式证书ID(SN) 签名证书ID
 *
 * @param string $unionpay_sign_cert_path 签名证书路径
 * @param string $unionpay_sign_cert_pwd 签名证书密码
 * @return unknown
 */
function getSignCertId($unionpay_sign_cert_path, $unionpay_sign_cert_pwd) {
	$pkcs12certdata = file_get_contents($unionpay_sign_cert_path);
	openssl_pkcs12_read( $pkcs12certdata, $certs, $unionpay_sign_cert_pwd );
	$x509data = $certs ['cert'];
	openssl_x509_read ( $x509data );
	$certdata = openssl_x509_parse( $x509data );
	$cert_id = $certdata ['serialNumber'];
	return $cert_id;
}

/**
 * 验证签名
 *
 * @param String $params_str 银联返回数据$_POST，包括$_POST ['signature'],$_POST ['certId']等
 *
 * @param string $unionpay_verify_cert_path 验证证书路径
  * @return boolean
*/
function verify($params, $unionpay_verify_cert_path) {
	// 公钥
	$public_key = getPulbicKeyByCertId ($params['certId'], $unionpay_verify_cert_path);
//	echo $public_key.'<br/>';
	// 签名串
	$signature_str = $params['signature'];
	unset($params['signature']);
	$params_str = ParamsToString ($params);
	$signature = base64_decode($signature_str);
	$params_sha1x16 = sha1($params_str, FALSE);
	$isSuccess = openssl_verify($params_sha1x16, $signature,$public_key, OPENSSL_ALGO_SHA1);
	return $isSuccess;
}

/**
 * 根据证书ID 加载cer证书文件
 *
 * @param string $certId
 * @param string $unionpay_verify_cert_path 验证证书路径
 * @return string NULL
 */
function getPulbicKeyByCertId($certId, $unionpay_verify_cert_path) {
	if(getVerifyCertId ($unionpay_verify_cert_path) == $certId) {
		return getPublicKey ($unionpay_verify_cert_path);
	}
	else {
		//echo 'Verify sign cert is incorrect';
		return NULL;
	}
}

/**
 * @desc 取.cert格式证书ID(SN) 验证证书ID
 *
 * @param string $unionpay_verify_cert_path 验证证书路径
 * @return string
 */
function getVerifyCertId($unionpay_verify_cert_path) {
	$x509data = file_get_contents( $unionpay_verify_cert_path );
	openssl_x509_read( $x509data );
	$certdata = openssl_x509_parse( $x509data );
	$cert_id = $certdata ['serialNumber'];
	return $cert_id;
}

/**
 * @desc 取证书公钥
 *
 * @param string $unionpay_verify_cert_path 验证证书路径
 * @return string
 */
function getPublicKey($unionpay_verify_cert_path) {
	return file_get_contents( $unionpay_verify_cert_path );
}


/**
 * @desc 数组排序后转化为字体串
 *
 * @param array $params
 * @return string
 */
function ParamsToString($params) {
	$sign_str = '';
	// 排序
	ksort($params);
	foreach($params as $key=>$val) {
		if($key == 'signature') {
			continue;
		}
		$sign_str .= sprintf("%s=%s&",$key,$val);
	}
	return substr($sign_str,0,strlen($sign_str)-1);
}

/**
 * @desc 字符串转换为数组
 *
 * @param string $str
 * @return array
 */
function StringToArray($str) {
	$result = array ();
	if( ! empty($str)) {
		$temp = preg_split('/&/', $str);
		if( ! empty($temp)) {
			foreach($temp as $key => $val) {
				$arr = preg_split('/=/', $val, 2);
				if( ! empty($arr)) {
					$k = $arr['0'];
					$v = $arr['1'];
					$result[$k] = $v;
				}
			}
		}
	}
	return $result;
}

/**
 * @desc 构造自动提交表单
 *
 * @param array $params
 * @param string $action
 * @return string
 */
function create_html($params, $action) {
	$encodeType = isset($params['encoding']) ? $params['encoding'] : 'UTF-8';
	$html = <<<eot
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset={$encodeType}" />
</head>
<title>准备支付</title>
<body>
    <div style="text-align:center">跳转中...</div>
    <form id="pay_form" name="pay_form" action="{$action}" method="post">

eot;
	foreach($params as $key => $value) {
		$html .= "    <input type=\"hidden\" name=\"{$key}\" id=\"{$key}\" value=\"{$value}\" />\n";
	}
	$html .= <<<eot
    </form>
    <script type="text/javascript">
        document.onreadystatechange = function(){
            if(document.readyState == "complete") {
                document.pay_form.submit();
            }
        };
    </script>
</body>
</html>
eot;
	return $html;
}

/**
 * @desc 后台交易 HttpClient通信
 *
 * @param array $params
 * @param string $url
 * @return mixed
 */
function sendHttpRequest($params, $url) {
	$opts = getRequestParamString ( $params );
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//不验证证书
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//不验证HOST
	curl_setopt($ch, CURLOPT_SSLVERSION, 3);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array(
			'Content-type:application/x-www-form-urlencoded;charset=UTF-8'
	) );
	curl_setopt($ch, CURLOPT_POSTFIELDS, $opts);

	/**
	 * 设置cURL 参数，要求结果保存到字符串中还是输出到屏幕上。
	 */
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

	// 运行cURL，请求网页
	$html = curl_exec($ch);
	// close cURL resource, and free up system resources
	curl_close($ch);
	return $html;
}

/**
 * @desc 组装报文
 *
 * @param array $params
 * @return string
 */
function getRequestParamString($params) {
	$params_str = '';
	foreach($params as $key => $value) {
		$params_str .= ($key . '=' . ( ! isset($value) ? '' : urlencode($value)) . '&');
	}
	return substr($params_str, 0, strlen($params_str) - 1);
}
